home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
- static char rcsid[] = "$Header: bobj.c,v 2.5 85/08/22 15:59:59 timo Exp $";
-
- /*
- * B editor -- A shrunken version of the B interpreter's run-time system.
- */
-
- #include "b.h"
- #include "bobj.h"
- #include "node.h"
-
- #define COMPOUNDS
-
- string malloc();
- string calloc();
- string realloc();
- string strcpy();
-
- extern bool dflag;
-
- struct head {
- char type;
- intlet refcnt;
- intlet len;
- };
- #define Intsize (sizeof(int))
- #define Hsize (sizeof(struct head))
- #define Headsize (((Hsize-1)/Intsize + 1) * Intsize)
-
- #define Field(v, i) (((value *)&(v)->cts)[i])
-
- #ifndef NDEBUG
-
- /* Statistics on allocation/sharing */
-
- int nobjs;
- int nrefs;
-
- #define Increfs ++nrefs
- #define Decrefs --nrefs
-
- #else NDEBUG
-
- #define Increfs
- #define Decrefs
-
- #endif NDEBUG
-
-
- #define Copy(v) if ((v) && Refcnt(v) < Maxintlet) { ++Refcnt(v); Increfs; }
- #define Release(v) if (!(v) || Refcnt(v) == Maxintlet) ; else RRelease(v)
- #define RRelease(v) \
- if (Refcnt(v) > 1) { --Refcnt(v); Decrefs; } else release(v)
-
-
- /*
- * Allocate a value with nbytes of data after the usual type, len, refcnt
- * fields.
- */
-
- value
- grabber(nbytes)
- register int nbytes;
- {
- register value v = (value) malloc((unsigned) (Headsize + nbytes));
-
- if (!v)
- syserr("grabber: malloc");
- #ifndef NDEBUG
- if (dflag)
- newval(v);
- #endif
- #ifndef NDEBUG
- ++nobjs;
- #endif
- Increfs;
- v->refcnt = 1;
- return v;
- }
-
-
- /*
- * Reallocate a value with nbytes of data after the usual type, len, refcnt
- * fields.
- */
-
- value
- regrabber(v, nbytes)
- register value v;
- register int nbytes;
- {
- Assert(v && v->refcnt == 1);
- v = (value) realloc((char*)v, (unsigned) (Headsize + nbytes));
- if (!v)
- syserr("regrabber: realloc");
- return v;
- }
-
-
- /*
- * Set an object's refcnt to infinity, so it will never be released.
- */
-
- fix(v)
- register value v;
- {
- register int i;
- register node n;
- register path p;
-
- Assert(v->refcnt > 0);
- #ifndef NDEBUG
- if (v->refcnt < Maxintlet)
- nrefs -= v->refcnt;
- #endif
- v->refcnt = Maxintlet;
- #if OBSOLETE
- switch (v->type) {
- case Tex:
- break;
- case Nod:
- n = (node)v;
- for (i = v->len - 1; i >= 0; --i)
- if (n->n_child[i])
- fix((value)(n->n_child[i]));
- break;
- case Pat:
- p = (path)v;
- if (p->p_parent)
- fix((value)(p->p_parent));
- if (p->p_tree)
- fix((value)(p->p_tree));
- break;
- #ifdef COMPOUNDS
- case Com:
- for (i = v->len-1; i >= 0; --i)
- if (Field(v, i))
- fix(Field(v, i));
- break;
- #endif COMPOUNDS
- #ifdef SLOW_INTS
- case Num:
- #endif SLOW_INTS
- default:
- Abort();
- }
- #endif OBSOLETE
- }
-
-
- #ifdef COMPOUNDS
- /*
- * Allocate a compound with n fields.
- */
-
- Visible value
- grab_com(n)
- int n;
- {
- value v = grabber(n*sizeof(value));
-
- v->type = Com;
- v->len = n;
- for (--n; n >= 0; --n)
- Field(v, n) = Vnil;
- return v;
- }
- #endif COMPOUNDS
-
-
- /*
- * Allocate a node with nch children.
- */
-
- node
- grab_node(nch)
- register int nch;
- {
- register node n = (node) grabber(
- sizeof(struct node) - Headsize +
- sizeof(value) * (nch-1));
- register int i;
-
- n->type = Nod;
- n->len = nch;
- n->n_marks = 0;
- n->n_width = 0;
- n->n_symbol = 0;
- for (i = nch-1; i >= 0; --i)
- n->n_child[i] = Nnil;
- return n;
- }
-
-
- /*
- * Allocate a path.
- */
-
- path
- grab_path()
- {
- register path p = (path) grabber(
- sizeof(struct path) - Headsize);
-
- p->type = Pat;
- p->p_parent = Pnil;
- p->p_tree = Nnil;
- p->p_ichild = 0;
- p->p_ycoord = 0;
- p->p_xcoord = 0;
- p->p_level = 0;
- p->p_addmarks = 0;
- p->p_delmarks = 0;
- return p;
- }
-
-
- #ifdef SLOW_INTS
- /*
- * Make an integer.
- */
-
- value
- mk_integer(i)
- int i;
- {
- value v;
- static value tab[128];
-
- if (!i)
- return Vnil;
- if (!(i&~127) && tab[i])
- return tab[i];
-
- v = grabber(sizeof(value));
- v->type = Num;
- Field(v, 0) = (value) i;
- if (!(i&~127)) {
- tab[i] = v;
- v->refcnt = Maxintlet;
- }
- return v;
- }
- #endif SLOW_INTS
-
-
- /*
- * Make a text object out of a C string.
- */
-
- value
- mk_text(str)
- register string str;
- {
- register int len = strlen(str);
- register value v = grabber(len+1);
-
- v->type = Tex;
- v->len = len;
- strcpy(Str(v), str);
- return v;
- }
-
-
- /*
- * Concatenate a C string to a text object (at the end).
- */
-
- concato(pv, str)
- register value *pv;
- register string str;
- {
- register value v = *pv;
- register int vlen = v->len;
- register int len = strlen(str);
-
- Assert(v && v->refcnt > 0);
- if (!len)
- return;
-
- len += vlen;
- if (v->refcnt == 1)
- v = regrabber(v, len+1);
- else {
- v = grabber(len+1);
- v->type = Tex;
- strcpy(Str(v), Str(*pv));
- Release(*pv);
- }
- strcpy(Str(v) + vlen, str);
- v->len = len;
- *pv = v;
- }
-
-
- /*
- * Return a substring (trim) of a text object.
- */
-
- value
- trim(v, behead, curtail)
- register value v;
- register int behead;
- register int curtail;
- {
- register value w;
- register int c;
-
- Assert(v && v->refcnt > 0);
- Assert(behead >= 0 && curtail >= 0 && behead+curtail <= v->len);
- if (behead + curtail == 0) {
- Copy(v);
- return v;
- }
-
- c = Str(v)[v->len - curtail];
- Str(v)[v->len - curtail] = 0; /* TEMPORARILY */
- w = mk_text(Str(v) + behead);
- Str(v)[v->len - curtail] = c;
- return w;
- }
-
-
- #ifdef SLOW_INTS
- /*
- * Return the C value if an integer object.
- */
-
- int
- intval(v)
- register value v;
- {
- if (!v)
- return 0;
- return (int) Field(v, 0);
- }
- #endif SLOW_INTS
-
-
- /*
- * Make sure a location (pointer variable) contains a unique object.
- */
-
- uniql(pv)
- register value *pv;
- {
- register value v = *pv;
- register value w;
- register path p;
- register node n;
- register int i;
-
- Assert(v && v->refcnt > 0);
- if (v->refcnt == 1)
- return;
-
- switch (v->type) {
-
- case Nod:
- n = grab_node(v->len);
- for (i = v->len - 1; i >= 0; --i) {
- w = (value) (n->n_child[i] = ((node)v)->n_child[i]);
- Copy(w); /* This is ugly */
- }
- n->n_marks = ((node)v)->n_marks;
- n->n_width = ((node)v)->n_width;
- n->n_symbol = ((node)v)->n_symbol;
- w = (value)n;
- break;
-
- case Pat:
- p = grab_path();
- p->p_parent = ((path)v)->p_parent;
- Copy(p->p_parent);
- p->p_tree = ((path)v)->p_tree;
- Copy(p->p_tree);
- p->p_ichild = ((path)v)->p_ichild;
- p->p_ycoord = ((path)v)->p_ycoord;
- p->p_xcoord = ((path)v)->p_xcoord;
- p->p_level = ((path)v)->p_level;
- w = (value)p;
- break;
-
- #ifdef SLOW_INTS
- case Num:
- w = mk_integer(intval(v));
- break;
- #endif SLOW_INTS
-
- #ifdef COMPOUNDS
- case Com:
- w = grab_com(v->len);
- for (i = v->len - 1; i >= 0; --i) {
- n = (node) (Field(w, i) = Field(v, i));
- Copy(n); /* This is uglier */
- }
- break;
- #endif COMPOUNDS
-
- case Tex:
- w = mk_text(Str(v));
- break;
-
- default:
- Abort();
-
- }
- Release(v);
- *pv = w;
- }
-
-
- /*
- * Increase the reference count of an object, unless it is infinite.
- */
-
- value
- copy(v)
- value v;
- {
- if (!v)
- return v;
-
- Assert(v->refcnt > 0);
- if (v->refcnt < Maxintlet) {
- ++v->refcnt;
- Increfs;
- }
- return v;
- }
-
-
- /*
- * Decrease the reference count of an object, unless it is infinite.
- * If it reaches zero, free the storage occupied by the object.
- */
-
- release(v)
- register value v;
- {
- register int i;
- register value w;
-
- if (!v)
- return;
- Assert(v->refcnt > 0);
- if (v->refcnt == Maxintlet)
- return;
-
- Decrefs;
- --v->refcnt;
- if (v->refcnt == 0) {
- switch (v->type) {
- #ifdef SLOW_INTS
- case Num:
- #endif SLOW_INTS
- case Tex:
- break;
- #ifdef COMPOUNDS
- case Com:
- for (i = v->len - 1; i >= 0; --i) {
- w = Field(v, i);
- Release(w);
- }
- break;
- #endif COMPOUNDS
- case Nod:
- for (i = v->len - 1; i >= 0; --i) {
- w = (value)(((node)v)->n_child[i]);
- Release(w);
- }
- break;
- case Pat:
- w = (value)(((path)v)->p_parent);
- Release(w);
- w = (value)(((path)v)->p_tree);
- Release(w);
- break;
- default:
- Abort();
- }
- #ifndef NDEBUG
- if (dflag)
- delval(v);
- --nobjs;
- #endif NDEBUG
- free((string)v);
- }
- }
-
- objstats()
- {
- #ifndef NDEBUG
- fprintf(stderr, "*** Object statistics: %d objects, %d references\n",
- nobjs, nrefs);
- #ifdef MSTATS
- mstats("(at end)"); /* A routine which some malloc versions have to print
- memory statistics. Remove if your malloc hasn't. */
- #endif MSTATS
- #endif NDEBUG
- }
-
- #ifndef NDEBUG
- valdump(v)
- value v;
- {
- if (!v)
- fputs("(nil)", stderr);
- else {
- fprintf(stderr, "v=0x%x, type='%c', len=%d, refcnt=",
- v, v->type, v->len);
- if (v->refcnt == Maxintlet)
- putc('*', stderr);
- else
- fprintf(stderr, "%d", v->refcnt);
- fputs(": ", stderr);
- wrval(v);
-
- }
- putc('\n', stderr);
- }
-
- #define QUOTE '\''
-
- wrval(v)
- value v;
- {
- register string cp;
- register int c;
-
- if (!v) {
- fputs("nil", stderr);
- return;
- }
-
- switch (v->type) {
-
- #ifdef SLOW_INTS
- case Num:
- fprintf(stderr, "%d", intval(v));
- break;
- #endif SLOW_INTS
-
- case Tex:
- putc(QUOTE, stderr);
- for (cp = Str(v); c = *cp; ++cp) {
- if (' ' <= c && c < 0177) {
- putc(c, stderr);
- if (c == QUOTE)
- putc(c, stderr);
- }
- else if (0 <= c && c < ' ')
- putc('^', stderr), putc(c + '@', stderr);
- else
- fprintf(stderr, "\\%03o", c);
- }
- putc(QUOTE, stderr);
- break;
-
- #ifdef COMPOUNDS
- case Com:
- {
- int i;
- value f;
- putc('(', stderr);
- for (i = 0; i < v->len; ++i) {
- if (i)
- putc(',', stderr), putc(' ', stderr);
- f = Field(v, i);
- if (!f || f->refcnt == 1 || f->type != Com) {
- if (f && f->type == Com)
- fprintf(stderr, "0x%x=", f);
- wrval(f);
- }
- else
- fprintf(stderr, "0x%x", f);
- }
- putc(')', stderr);
- break;
- }
- #endif COMPOUNDS
-
- default:
- fprintf(stderr, "0x%x", v);
-
- }
- }
-
- static struct list {
- struct list *link;
- value val;
- } head;
- #endif NDEBUG
-
- objdump()
- {
- #ifndef NDEBUG
- struct list *l;
-
- for (l = head.link; l; l = l->link)
- valdump(l->val);
- #endif NDEBUG
- }
-
- objcheck()
- {
- #ifndef NDEBUG
- struct list *l;
-
- for (l = head.link; l; l = l->link)
- if (l->val->refcnt != Maxintlet)
- valdump(l->val);
- #endif NDEBUG
- }
-
- #ifndef NDEBUG
- newval(v)
- register value v;
- {
- register struct list *l =
- (struct list *) malloc((unsigned) sizeof(struct list));
-
- if (!l)
- syserr("newval: malloc");
- l->link = head.link;
- l->val = v;
- head.link = l;
- }
-
- delval(v)
- register value v;
- {
- register struct list *l;
- register struct list *p;
-
- for (p = &head, l = head.link; l; p = l, l = l->link) {
- if (l->val == v) {
- p->link = l->link;
- free((string)l);
- return;
- }
- }
- Abort();
- }
- #endif NDEBUG
-